package com.atguigu.gmall.cart.service.impl;
import com.atguigu.gmall.cart.vo.AddSuccessVo.CartItemVo;

import com.atguigu.gmall.cart.entity.CartInfo;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.cart.vo.AddSuccessVo;
import com.atguigu.gmall.cart.vo.UserAuth;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.HttpUtil;
import com.atguigu.gmall.common.util.JSONs;
import com.atguigu.gmall.common.util.UserAuthUtil;
import com.atguigu.gmall.feign.product.SkuInfoFeignClient;
import com.atguigu.gmall.product.entity.SkuInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author lfy
 * @Description
 * @create 2023-07-31 9:32
 */
@Slf4j
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    StringRedisTemplate redisTemplate;


    @Autowired
    SkuInfoFeignClient skuInfoFeignClient;

    @Autowired
    ThreadPoolExecutor executor;

    @Override
    public String determinCartKey() {

        HttpServletRequest request = HttpUtil.currentRequest();
        String userid = request.getHeader(RedisConst.USER_ID_HEADER);
        String tempid = request.getHeader(RedisConst.USER_TEMPID_HEADER);
        log.info("service-cart 用户 id:{} ,temp:{} 给购物车中添加商品 ",userid,tempid);

        //1、给哪个购物车添加 2、添加哪个商品  3、添加几件
        String cartKey = "";
        if(StringUtils.hasText(userid)){
            cartKey = RedisConst.CART_INFO+userid;
        }else {
            cartKey = RedisConst.CART_INFO+tempid;
        }

        return cartKey;
    }

    @Override
    public AddSuccessVo addItemToCart(String cartKey, Long skuId, Integer skuNum) {
        //把一个商品添加到指定购物车
        BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(cartKey);

        CartInfo cartInfo = null;
        //判断是否是新增商品
        if (!hashOps.hasKey(skuId.toString())) {
            //1、把商品添加到购物车【商品新增】
            //1.1）、远程获取商品数据
            Result<SkuInfo> result = skuInfoFeignClient.getSkuInfo(skuId);
            //1.2）、封装数据
            cartInfo = convertSkuInfoToCartInfo(result.getData());
            cartInfo.setSkuNum(skuNum);
            //1.3）、保存到redis
            saveCartItem(cartKey,cartInfo);
//            hashOps.put(skuId.toString(), JSONs.obj2JsonStr(cartInfo));
        }else {
            //2、如果购物车之前已经加过这个商品，只需要增加数量即可
            //2.1）、获取redis中保存的这个商品json
            String json = hashOps.get(skuId.toString());
            cartInfo = JSONs.jsonStr2Obj(json, CartInfo.class);
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);

            //以前购物车的商品的价格有可能发生变化了，所以需要同步一下最新价格;
            Result<BigDecimal> skuPrice = skuInfoFeignClient.getSkuPrice(skuId);
            cartInfo.setSkuPrice(skuPrice.getData());

            //2.2）、保存到redis中  //【细节-单个商品限购】
            saveCartItem(cartKey,cartInfo);
//            String jsonStr = JSONs.obj2JsonStr(cartInfo);
//            hashOps.put(skuId.toString(),jsonStr);
        }


        //设置购物车的过期时间
        UserAuth auth = UserAuthUtil.getUserAuth();
        if(!StringUtils.hasText(auth.getUserid())){
            //userid是空的。 cartKey一定就是临时的key，需要设置1年过期时间 自动延期
            //临时购物车是最后一次操作 延后一年 都不操作，才销毁
            redisTemplate.expire(cartKey, Duration.ofDays(365)); //自动延期 【细节-临时购物车1年过期】

//            Long expire = redisTemplate.getExpire(cartKey);
//            if(expire == -1){  //这么写没有自动延期
//                redisTemplate.expire(cartKey, Duration.ofDays(365));
//            }
        }

        return   convertCartInfoToSuccessVO(cartInfo);

    }

    @Override
    public List<CartInfo> cartList(String cartKey) {



        BoundHashOperations<String, Object, Object> hashOps =
                redisTemplate.boundHashOps(cartKey);

        List<CartInfo> list = hashOps.values().stream()
                .map(item -> {
                    CartInfo cartInfo = JSONs.jsonStr2Obj(item.toString(), CartInfo.class);
                    //远程查询最新价格。 页面此时看不到最新价格，下一次刷新才能看到
                    //数据一致性要求不高
                    CompletableFuture.runAsync(()->{
                        log.info("购物车商品【{}】，正在查询最新价格",cartInfo.getSkuId());
                        BigDecimal price = skuInfoFeignClient.getSkuPrice(cartInfo.getSkuId()).getData();
                        if(!price.equals(cartInfo.getSkuPrice())){
                            cartInfo.setSkuPrice(price);
                            saveCartItem(cartKey,cartInfo);
                            log.info("商品【{}】价格发生了变化，正在更新到购物车【{}】",cartInfo.getSkuId(),cartKey);
                        }
                    },executor);
                    return cartInfo;
                })
                .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                .collect(Collectors.toList());

        return list;
    }

    @Override
    public void updateNum(String cartKey, Long skuId, Integer num) {
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(cartKey);
        //1、获取购物车中指定商品
        CartInfo cartInfo = getCartItem(cartKey,skuId);

        //修改数量
        cartInfo.setSkuNum(cartInfo.getSkuNum() + num);

        //2、保存商品到购物车
        saveCartItem(cartKey,cartInfo);

    }

    @Override
    public void updateStatus(String cartKey, Long skuId, Integer status) {
        CartInfo cartItem = getCartItem(cartKey, skuId);

        cartItem.setIsChecked(status);

        saveCartItem(cartKey,cartItem);

    }

    @Override
    public void deleteCartInfo(String cartKey, Long skuId) {
        BoundHashOperations<String, String, String> cart = getCart(cartKey);

        cart.delete(skuId.toString());
    }

    @Override
    public void deleteChecked(String cartKey) {
        BoundHashOperations<String, String, String> cart = getCart(cartKey);


        //1、获取所有选中商品的id
        List<String> checkedIds = cart.values().stream()
                .map(json -> JSONs.jsonStr2Obj(json, CartInfo.class))
                .filter(item -> item.getIsChecked() == 1) // cartinfo
                .map(item -> item.getSkuId().toString()) //long
                .collect(Collectors.toList());

        cart.delete(checkedIds.toArray());

    }

    @Override
    public void mergeCart() {
        UserAuth auth = UserAuthUtil.getUserAuth();
        if(!StringUtils.hasText(auth.getUserid())){
            //用户没有登录无需进行合并
            return;
        }

        //1、既有临时id，又有用户id
        //1)、当前用户的临时购物车
//        BoundHashOperations<String, String, String> userCart = getCart(RedisConst.CART_INFO + userid);

        //2）、当前用户的用户购物车
        BoundHashOperations<String, String, String> tempCart = getCart(RedisConst.CART_INFO + auth.getTempid());

        //3）、如果临时购物车有数据，需要把数据移动到用户购物车
        if (tempCart.size()>0) {
            //合并购物车
            List<CartInfo> infos = cartList(RedisConst.CART_INFO + auth.getTempid());
            for (CartInfo info : infos) {
                try{
                    //把临时购物车的每个商品都添加到用户购物车
                    addItemToCart(RedisConst.CART_INFO + auth.getUserid(),info.getSkuId(),info.getSkuNum());
                }catch (GmallException e){
                    //合并期间出现数量超出限制异常。进行业务兜底
                    //1、啥也不写； 错误的合并记录会被跳过
                    //2、单品数量超限，改到最大值
                    if (e.getCode() == ResultCodeEnum.CART_ITEM_OVERFLOW.getCode()) {
                        info.setSkuNum(RedisConst.CART_SIZE); //设置到最大值,直接保存到redis
                        saveCartItem(RedisConst.CART_INFO + auth.getUserid(),info);
                    }
                    //3、品类超限，跳过这个商品合并
                }
            }
            //清空临时购物车
            redisTemplate.delete(RedisConst.CART_INFO + auth.getTempid());

        }

        //啥也不用做

    }

    @Override
    public List<CartInfo> getChecked(String cartKey) {

        BoundHashOperations<String, String, String> cart = getCart(cartKey);

        List<CartInfo> infos = cart.values()
                .stream()
                .map(json -> JSONs.jsonStr2Obj(json, CartInfo.class))
                .filter(item -> item.getIsChecked() == 1)
                .collect(Collectors.toList());

        return infos;
    }


    /**
     * 给购物车保存一个 cartInfo
     * @param cartKey
     * @param cartInfo
     */
    private void saveCartItem(String cartKey, CartInfo cartInfo) {
        BoundHashOperations<String, String, String> cart = getCart(cartKey);
        if(cartInfo.getSkuNum() > RedisConst.CART_SIZE){
           throw new GmallException(ResultCodeEnum.CART_ITEM_OVERFLOW);
        }
        if (cart.size()+1 > RedisConst.CART_SIZE) {
            throw new GmallException(ResultCodeEnum.CART_SIZE_OVERFLOW);
        }
        cart.put(cartInfo.getSkuId().toString(),JSONs.obj2JsonStr(cartInfo));

    }

    private BoundHashOperations<String, String, String> getCart(String cartKey) {
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(cartKey);
        return hashOps;
    }

    private CartInfo getCartItem(String cartKey, Long skuId) {
        BoundHashOperations<String, String, String> cart = getCart(cartKey);

        String json = cart.get(skuId.toString());

        return JSONs.jsonStr2Obj(json, CartInfo.class);
    }

    private AddSuccessVo convertCartInfoToSuccessVO(CartInfo cartInfo) {
        AddSuccessVo successVo = new AddSuccessVo();
        CartItemVo itemVo = new CartItemVo();
        itemVo.setSkuDefaultImg(cartInfo.getImgUrl());
        itemVo.setSkuName(cartInfo.getSkuName());
        itemVo.setId(cartInfo.getSkuId());


        successVo.setSkuInfo(itemVo);
        successVo.setSkuNum(cartInfo.getSkuNum());


        return successVo;
    }

    private CartInfo convertSkuInfoToCartInfo(SkuInfo data) {
        CartInfo cartInfo = new CartInfo();

        cartInfo.setSkuId(data.getId());
        cartInfo.setCartPrice(data.getPrice());
        cartInfo.setSkuPrice(data.getPrice());
        cartInfo.setImgUrl(data.getSkuDefaultImg());
        cartInfo.setSkuName(data.getSkuName());
        cartInfo.setIsChecked(1); //默认就是选中
        cartInfo.setCreateTime(new Date());
        cartInfo.setUpdateTime(new Date());

        return cartInfo;
    }
}
